package cc.rengu.igas.channel.wechat.core.service.trans;


import cc.rengu.igas.channel.wechat.common.constant.WechatConfigConstant;
import cc.rengu.igas.channel.wechat.common.constant.WechatParamConstant;
import cc.rengu.igas.channel.wechat.common.constant.WechatTreeNodeConstant;
import cc.rengu.igas.channel.wechat.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.wechat.core.model.ChnlBizResponse;
import cc.rengu.igas.channel.wechat.core.service.base.PayService;
import cc.rengu.igas.channel.wechat.facade.request.WechatUnifiedOrderRequest;
import cc.rengu.igas.channel.wechat.facade.response.WechatUnifiedOrderResponse;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;

import java.net.InetAddress;
import java.util.*;


/**
 * 统一下单
 */
public class UnifiedOrderService extends PayService {

    @Override
    protected Object beforeBizProcess() throws Exception {
        WechatUnifiedOrderRequest unifiedOrderRequest = new WechatUnifiedOrderRequest();
        ConvertUtil.convertOutput(unifiedOrderRequest);
        return unifiedOrderRequest;
    }

    @Override
    protected ChnlBizResponse callBizService(Object request) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        int iReturnCode = 0;

        WechatUnifiedOrderResponse unifiedOrderResponse = new WechatUnifiedOrderResponse();
        WechatUnifiedOrderRequest unifiedOrderRequest = (WechatUnifiedOrderRequest) request;
        String instId = unifiedOrderRequest.getHeader().getInstId();
        DstChannelCfg dstChannelCfg = (DstChannelCfg) xmlTreeUtil.getXmlTreeObjectValue(WechatTreeNodeConstant.DST_CHANNEL_CFG, DstChannelCfg.class);
        DstChannelInfo dstChannelInfo = (DstChannelInfo) xmlTreeUtil.getXmlTreeObjectValue(WechatTreeNodeConstant.DST_CHANNEL_INFO, DstChannelInfo.class);
        if (unifiedOrderRequest.getTermIp() == null || unifiedOrderRequest.getTermIp().trim().isEmpty()) {
            //赋值本机服务器IP
            InetAddress addr = InetAddress.getLocalHost();
            unifiedOrderRequest.setTermIp(addr.getHostAddress());
        }
        ConvertUtil.convertInput(unifiedOrderRequest);
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, unifiedOrderRequest.getHeader().getTxnNum());
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_CHANNEL_NO, dstChannelCfg.getChannelNo());
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_MCHNT_NO, dstChannelCfg.getProviderMchntNo());
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_APP_ID, dstChannelCfg.getAppId());
        if (!StringUtil.isEmptyOrNull(dstChannelCfg.getOtherConfParam())) {
            JSONObject jsonObject = JSONObject.parseObject(dstChannelCfg.getOtherConfParam());
            xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_CHANNEL_NAME, jsonObject.getString(WechatTreeNodeConstant.WX_CHANNEL_NAME));
        }
        //TODO:先特殊一下，要改
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_SUB_OPEN_ID, unifiedOrderRequest.getOpenId());

        SysParamService sysParamService = new SysParamServiceImpl();
        SysParam sysParam = null;
        if (ChannelEnum.NUWX.getChannelType().equals(unifiedOrderRequest.getChannelId())) {
            sysParam = sysParamService.getSysParamInfo(instId, WechatConfigConstant.NUCC_WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_NOTICE_URL);
            if (sysParam == null) {
                rglog.error("未配置异步通知地址，请配置");
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
            SysParam sysParamUrl = sysParamService.getSysParamInfo(instId, WechatConfigConstant.NUCC_WECHAT_URL_CONF_NODE, unifiedOrderRequest.getHeader().getTxnNum() + unifiedOrderRequest.getIdcFlag());
            if (sysParamUrl == null) {
                rglog.error("未配置网联交易<{}>地址idc标志<{}>，请配置", unifiedOrderRequest.getHeader().getTxnNum(), unifiedOrderRequest.getIdcFlag());
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
            xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE, sysParamUrl.getParamValue());

        } else if (ChannelEnum.UPWX.getChannelType().equals(unifiedOrderRequest.getChannelId())) {
            sysParam = sysParamService.getSysParamInfo(instId, WechatConfigConstant.CUPS_WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_NOTICE_URL);
            if (sysParam == null) {
                rglog.error("未配置异步通知地址，请配置");
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
        } else {
            sysParam = sysParamService.getSysParamInfo(instId, WechatConfigConstant.WECHAT_CONF_NODE, WechatConfigConstant.WECHAT_NOTICE_URL);
            if (sysParam == null) {
                rglog.error("未配置异步通知地址，请配置");
                throw new BizException(RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespCode(), RespCodeEnum.CONFIG_PARAM_NOT_EXIST.getRespDesc());
            }
        }
        xmlTreeUtil.setXmlTreeStringValue(WechatTreeNodeConstant.WX_NOTIFY_URL, sysParam.getParamValue());//+"/"+unifiedOrderRequest.getHeader().getChanlId());
        rglog.debug("WX_NOTIFY_URL = <{}>", xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_NOTIFY_URL));
        iReturnCode = schedule.callService(dstChannelInfo.getDstServiceName(), 0);
        if (xmlTreeUtil.isExist(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE)) {
            xmlTreeUtil.deleteXmlTreeNode(WechatTreeNodeConstant.DEFINE_HTTP_URL_NODE);
        }
        if (0 != iReturnCode && 98 != iReturnCode) {
            rglog.error("调用微信服<{}>失败，iReturnCode:<{}>", dstChannelInfo.getDstServiceName(), iReturnCode);
            throw new BizException(RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), RespCodeEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        } else if (98 == iReturnCode) {
            rglog.error("调用微信服<{}>超时，iReturnCode:<{}>", dstChannelInfo.getDstServiceName(), iReturnCode);
            throw new BizException(RespCodeEnum.TIME_OUT_ERROR.getRespCode(), RespCodeEnum.TIME_OUT_ERROR.getRespDesc());
        }
        ConvertUtil.convertOutput(unifiedOrderResponse);
        String resultCode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_RESULT_CODE);
        String returnCode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_RETURN_CODE);
        String returnMsg = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_RETURN_MSG);
        String errCode = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_CODE);
        String errMsg = xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_ERR_MSG);
        if (!WechatParamConstant.STRING_SUCCESS.equals(resultCode)) {
            unifiedOrderResponse.setRespCode((null == errCode) ? returnCode : errCode);
            unifiedOrderResponse.setRespDesc((null == errMsg) ? returnMsg : errMsg);
            rglog.error("调用第三方服务失败,respCode=[{}],respDesc=[{}]", unifiedOrderResponse.getRespCode(), unifiedOrderResponse.getRespDesc());
        } else {
            unifiedOrderResponse.setRespCode(RespCodeEnum.TRANS_SUCCESS.getRespCode());
            unifiedOrderResponse.setRespDesc(RespCodeEnum.TRANS_SUCCESS.getRespDesc());
        }
        rglog.debug("赋值wechatPayInfo=<{}>", xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_WC_PAY_DATA));
        unifiedOrderResponse.setWechatpayInfo(xmlTreeUtil.getXmlTreeStringValue(WechatTreeNodeConstant.WX_WC_PAY_DATA));

        if (ChannelEnum.WXZF.getChannelType().equals(unifiedOrderRequest.getChannelId()) &&
                ("JSAPI".equals(unifiedOrderRequest.getTradeType()) || "APP".equals(unifiedOrderRequest.getTradeType()))) {
            unifiedOrderResponse.setWechatpayInfo(genPayInfo(dstChannelCfg));
        }
        ChnlBizResponse chnlBizResponse = new ChnlBizResponse();
        chnlBizResponse.setResult(unifiedOrderResponse);
        return chnlBizResponse;
    }

    @Override
    protected void afterBizProcess(ChnlBizResponse response) throws Exception {
        WechatUnifiedOrderResponse unifiedOrderResponse = (WechatUnifiedOrderResponse) response.getResult();
        ConvertUtil.convertInput(unifiedOrderResponse);
    }

    private String genPayInfo(DstChannelCfg dstChannelCfg) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        JSONObject object = new JSONObject();
        object.put("appId", dstChannelCfg.getAppId());
        String tm = String.valueOf(System.currentTimeMillis());
        object.put("timeStamp", tm.substring(0, 10));
        object.put("nonceStr", RandomUtil.getRandomStr(32));
        String prepayId = xmlTreeUtil.getXmlTreeStringValue("prepayId");
        String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        if (prepayId == null) {
            rglog.error("未返回prepayId");
            return null;
        }
        String packageinfo = "prepay_id=" + prepayId;
        object.put("package", packageinfo);
        object.put("signType", "MD5");
        String jsonstr = object.toJSONString();
        Map<String, String> map1 = JSON.parseObject(jsonstr, Map.class, Feature.OrderedField);
        int i;
        ArrayList<String> arrayTmp = new ArrayList<>();
        for (Map.Entry<?, ?> entry : map1.entrySet()) {
            String strValue = (String) entry.getValue();
            if (strValue != null && !"".equals(strValue)) {
                arrayTmp.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }

        String[] strArray = arrayTmp.toArray(new String[0]);
        Arrays.sort(strArray);

        StringBuilder strBuf = new StringBuilder();
        for (i = 0; i < strArray.length; i++) {
            strBuf.append(strArray[i]);
        }
        strBuf.append("key=");
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(instId, dstChannelCfg.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(WechatParamConstant.SIGN_KEY_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(secPlanInfoOpt.get().getInstId() + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                if (keyInfo != null) {
                    strBuf.append(keyInfo.getKeyValue());
                }
            }
        }
        String signBlock = strBuf.toString();
        rglog.error("signBlock=[{}]", signBlock);
        String paysign = MD5Util.generateSignString(signBlock);
        if (paysign == null) {
            rglog.error("生成paysign失败");
            return null;
        }
        object.put("paySign", paysign);
        return object.toString();
    }
}
